// file:src/include/os/fatfsio.h
// autor:jiangxinpeng
// time:2021.2.28
// copyright:(C) by jiangxinpeng,All right are reserved.

#ifndef OS_FATFSIO_H
#define OS_FATFSIO_H

#include <lib/type.h>
#include <os/fatconfig.h>
#include <os/semaphore.h>
#include <os/diskman.h>

// file open and access mode
#define FA_OPEN_EXISTING 0x00
#define FA_READ 0x01
#define FA_WRITE 0x02
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08 // always create new file
#define FA_OPEN_ALWAYS 0x10   // if is file present,open file,or create new
#define FA_OPEN_APPEND 0x20
#define FA_SEEKED 0x40
#define FA_MODIFIED 0x80
#define FA_DIRTY 0x100

// format type
#define FM_FAT 0x01
#define FM_FAT32 0x02
#define FM_EXFAT 0x04
#define FM_ANY 0x07
#define FM_SFD 0x08

// cluster limit
#define FAT12_CLUST_MAX 0xFF5      // max clust of fat12
#define FAT16_CLUST_MAX 0xFFF5     // max clust of fat16
#define FAT32_CLUST_MAX 0x0FFFFFF5 // max clust of fat32
#define EXFAT_CLUST_MAX 0x7FFFFFFD // max clust of exbpb

// dir max size
#define FAT_DIR_MAX 0x200000     // max size of FAT director
#define EXFAT_DIR_MAX 0x10000000 // max size of EXFAT director

// check volume id type
#define isdigit(ch) (ch >= '0' && ch <= '9')
#define IS_CHAR(ch) ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
#define DIRIDX_VAILD(idx) ((idx) > ((fs->fs_type == FS_EXFAT) ? EXFAT_DIR_MAX : FAT_DIR_MAX)) || ((idx) % DIR_TERN_SIZE)

// logic driver to pyhics driver
#define LD2PD(disk) ((uint8_t)DiskSoltFindDiskById(disk))  // if is disk,return disk solt,otherwise,return vol associate physical driver solt
#define LD2PT(disk) ((uint8_t)(DiskSoltFindVolById(disk))) // if is vol,return vol solt,otherwise,return -1(disk device)

#define DIR_TERN_SIZE 32                            // size of fat dir size
#define DDEM 0xE5                                   // delete director tern mask
#define RDDEM 0x05                                  // replacment the character with RDDEM
#define LLEF 0x40                                   // last long name entry flags
#define FS_LFN_LEN 128                              // LFN name length
#define FS_LFN_BUFF_MAX 256                         // buffer max of LFN
#define MALLOC_MAX 0x8000                           // max buffer malloc size (must be > SECTOR_SIZE)
#define MAXDIR(nc) ((nc + 45) / 15 * DIR_TERN_SIZE) // size of director entry block

#define SEC_PER_TRACK 63
#define GPT_ALIGN 0x100000 // alignment of partitions in GPT
#define GPT_ENTRY_SIZE 128 // size of partition table entry in GPT
#define GPT_ITEMS 128      // number of partition table entry in GPT
#define MBR_ENTRY_SIZE 4   // size of partition table entry in MBR

// character code support
#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z')
#define IsLower(c) ((c) >= 'a' && (c) <= 'z')
#define IsDight(c) ((c) >= '0' && (c) <= '9')
#define IsSurrogate(c) ((c) >= 0xD800 && (c) <= 0xDFFF)
#define IsSurrogateH(c) ((c) >= 0xD800 && (c) <= 0xDBFF)
#define IsSurrogateL(c) ((c) >= 0xDC00 && (C) <= 0xDFFF)

// file system type
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
#define FS_EXFAT 4

// name status flags
#define NSFLAGS 11     // index of name status byte
#define NS_LOSS 0x01   // out of 8.3 format
#define NS_LFN 0x02    // force to create LFN entry
#define NS_LAST 0x04   // last segment
#define NS_BODY 0x08   // lower case flags (body)
#define NS_EXT 0x10    // lower case flags (ext)
#define NS_DOT 0x20    // Dot entry
#define NS_NOLFN 0x40  // don't find LFN
#define NS_NONAME 0x80 // not follow

// exFAT director entry type
#define EXFAT_BITMAP 0x81   // allocation bitmap
#define EXFAT_UPCASE 0x82   // up-case table
#define EXFAT_VOLLABEL 0x83 // volume label
#define EXFAT_STREAM 0xC0   // stream extension
#define EXFAT_FILEDIR 0x85  // file/director
#define EXFAT_FILENAME 0xC1 // name extension

#define FAT_TIME_HOUR(val) (uint32_t)(((val) >> 11) & 0x1f)
#define FAT_TIME_MIN(val) (uint32_t)(((val) >> 5) & 0x3f)
#define FAT_TIME_SEC(val) (uint32_t)(((val)&0x1F) * 2)

#define FAT_TIME_YEAR(val) (uint32_t)((((val) >> 9) & 0x7f) + 1980)
#define FAT_TIME_MON(val) (uint32_t)(((val) >> 5) & 0xF)
#define FAT_TIME_DAY(val) (uint32_t)((val)&0x1F)

// fs check result
typedef enum fscheck
{
    FS_FATVBR = 0,
    FS_EXFATVBR,
    FS_VAILDBS,
    FS_NOFAT,
    FS_INVAILDBS,
    FS_DISKERR,
} fscheck_t;

typedef enum
{
    FSTU_OK = 0,           // succeed
    FSTU_DISK_ERR,         // hard driver error
    FSTU_INT_ERR,          // assertion faild
    FSTU_NOT_READY,        // phyhics driver cannot work
    FSTU_NOT_FILE,         // file not present
    FSTU_NO_PATH,          // path not present
    FSTU_INVALID_NAME,     // path name format error
    FSTU_DENIED,           // access denied
    FSTU_EXIST,            // access denied
    FSTU_INVALID_OBJ,      // file/director obj no invalid
    FSTU_WRITE_PROTECT,    // pyhics driver is write protect
    FSTU_INVALID_DRIVER,   // logical driver number is invalid
    FSTU_NO_FILESYSTEM,    // volume invalid
    FSTU_BUFFER_ERROR,     // lfn buffer alloc failed
    FSTU_MKFS_ABORT,       // mkfs error
    FSTU_INVALID_PARMETER, // mkfs parme erro
} file_status_t;

typedef enum
{
    FNAME_NONAME = (1 << 0), // no name
} file_name_status_t;

enum file_attribute
{
    ATT_RDONLY = 0x01,                                       // read only
    ATT_HIDDEN = 0x02,                                       // hidden
    ATT_SYS = 0x04,                                          // system
    ATT_VOL = 0x08,                                          // volume id
    ATT_FDIR = 0x10,                                         // director
    ATT_ARCHIVE = 0x20,                                      // archive
    ATT_LFN = (ATT_RDONLY | ATT_HIDDEN | ATT_SYS | ATT_VOL), // long filename
    ATT_MASK = 0x3F,                                         // mask
};

// fat file system
typedef struct
{
    uint8_t fs_type;         // file system type  0:unmount 1:mount
    uint8_t pydrv;           // fs on driver
    uint8_t fat_num;         // fat count
    uint8_t flags;           // flags
    uint8_t wflags;          // win[] flags     0:dirty
    lba_t winsec;            // current sectors in win[]
    uint8_t err;             // error
    uint8_t win[FS_SEC_MAX]; // win buffer
    uint8_t fsinfo_flags;    // fsinfo flags
    uint8_t vol_id;          // vol id
    uint16_t rootdir_num;    // root director num(only fat12/16 need)
    uint16_t clust_size;     // sizes of cluster
    uint16_t sector_size;    // sizes of sector
    uint16_t *lfn_buff;      // len file name buffer
    uint8_t *dir_buff;       // director entry buffer
    uint64_t last_clust;     // last alloc cluster
    uint64_t free_clust;     // numbers of free cluster
    uint64_t cur_dir;        // current dir(0: root director)
    uint64_t fat_entrys;     // fat entry count
    uint64_t fsinfo_start;   // fsinfo start sector(fat32: only support)
    uint64_t fat_start;      // fat start sector
    uint64_t vol_start;      // vol start sector
    uint64_t dir_start;      // dir start sector/cluster(for FAT32,just is rootdir cluster)
    uint64_t data_start;     // data start sector
    uint64_t fat_size;       // size of fats(total size)

    uint32_t cd_clust; // containing director start cluster
    uint32_t cd_size;  // size of containing director
    uint32_t cd_off;   // off in containing director
    lba_t bitbase;     // allocation bitmap base sector
} fatfs_t;

// file object identifiy
typedef struct
{
    fatfs_t *fs;     // point file system
    uint16_t vol_id; // volume id
    uint8_t attr;    // file attr
    uint8_t status;  // object status
    uint32_t clust;  // file cluster
    uint32_t size;   // file size

    // EXFAT
    uint32_t n_count; // size of first fragment
    uint32_t n_frag;  // size of last fragment
    uint32_t c_clust; // containing director strat cluster
    uint32_t c_size;  // size of containing director size
    uint32_t c_off;   // offset in containing director
} file_id_t;

// file object
typedef struct
{
    file_id_t obj;
    uint32_t flags;
    uint8_t err;
    uint32_t fptr;
    uint64_t clust;
    uint64_t sector;
    uint64_t dir_sec;
    uint8_t *dir_ptr;
    uint64_t *cltbl;
    uint8_t buff[FS_SEC_MAX];
} file_obj_t;

// dir object
typedef struct
{
    file_id_t obj;      // object
    uint32_t id;        // file object id
    uint64_t off;       // current read/write offset
    uint64_t clust;     // current cluster
    uint64_t sector;    // current sector
    uint8_t *dir;       // dir point
    uint8_t fn[12];     // SFN
    uint32_t block_off; // offset of current entry
} dir_obj_t;

// file information structure
typedef struct
{
    uint32_t size; // file  size(bytys)
    uint16_t date; // file date
    uint16_t time; // file time
    uint8_t attr;  // file attribute

    char fname[FS_LFN_BUFF_LEN];   // primary file name
    char altname[FS_SFN_BUFF_LEN]; // alt file name
} file_info_t;

#pragma pack(push, 1)
typedef struct // 8.3 file name
{
    uint8_t name[11];    // 8.3 filename
    uint8_t attr;        // attr
    uint8_t flag;        // lower case
    uint8_t ctime_sub;   // create time in tenths of a second
    uint16_t ctime;      // create time(hour:5bits minutes:6bits seconds:5bits)
    uint16_t cdate;      // create data(year:7bits months:4bits day:5bits)
    uint16_t atime;      // access time
    uint16_t clust_high; // high 16bits of cluster
    uint16_t mtime;      // last modifiy time
    uint16_t mdate;      // last modifiy date
    uint16_t clust_low;  // low 16bits of cluster
    uint32_t size;       // size of fiile
} dir_info_t;
#pragma pack(pop)

#pragma pack(push, 1)
typedef struct
{
    uint8_t type; // type of EXFAT director entry
    union
    {
        struct // volume label director entry
        {
            uint8_t length;    // number of volume label
            uint8_t label[15]; // volume label
        } xdir_label;

        struct // bitmap director entry
        {
            uint8_t flags; // FAT table(0:FAT1 1:FAT2)
            uint8_t res[18];
            uint32_t cluster;
            uint64_t length;
        } xdir_bitmap;

        struct // upper table
        {
            uint8_t res0[3];
            uint32_t chksum;
            uint8_t res1[3];
            uint32_t cluster;
            uint64_t length;
        } xdir_upper;

        struct // file attribute director entry1
        {
            uint8_t num_dir; // number of addition director entries
            uint16_t chksum; // checksum
            uint8_t attr;    // attr
            uint8_t reserved0[3];
            uint32_t ctime; // create time
            uint32_t mtime; // last modify time
            uint32_t atime; // last access time
            uint8_t reserved1[12];
        } xdir_primary;

        struct // file attribute director entry2
        {
            uint8_t flags; // cluster chain in FAT flags
            uint8_t reserved0;
            uint8_t name_len;     // file name length
            uint16_t name_chksum; // file name checksum
            uint8_t reserved1[2];
            uint64_t size; // file length
            uint8_t reserved2[4];
            uint32_t cluster; // file start clust
            uint64_t lenght;  // file lenth
        } xdir_seconday;

        struct // file name director entries
        {
            uint8_t entry_count;
            uint16_t name[15]; // file name
        } xdir_name;
    } xdir_dir;
} xdir_info_t;
#pragma pack(pop)

#pragma pack(push, 1)
typedef struct // fat32 long file name
{
    uint8_t order;     // filename order
    uint16_t name0[5]; // filename unicode code
    uint8_t attr;      // attribute
    uint8_t type;      // type
    uint8_t checksum;  // checksum
    uint16_t name1[6]; // filename unicode code
    uint16_t start;    // start clust,usual be set to 0
    uint16_t name2[2]; // filename unicode code
} dir_info_lfn_t;
#pragma pack(pop)

// FAT/FAT32 boot block
#pragma pack(push, 1)
typedef struct bpb
{
    uint8_t jmp[3];          // jmp instruction
    uint8_t oem[8];          // oem filed
    uint16_t bytes_per_sec;  // bytes per sector
    uint8_t sec_per_clust;   // sectors per cluster
    uint16_t reserved_sec;   // reserved sectors
    uint8_t fat_num;         // file alloc table count
    uint16_t rootdir_number; // number of root dir cluster
    uint16_t total_sector;   // if equal 0x00,actor count in large_sec_count
    uint8_t media;           // media descript type
    uint16_t fat_size16;     // sector per fat
    uint16_t sec_per_track;  // sectors per track
    uint16_t head;           // how much heads
    uint32_t start_lba;      // volume start lba address
    uint32_t large_sector;   // large sector count,if total_seccount equal 0x00,we use it
    union
    {
        struct
        {
            uint32_t fat_size32;       // sectors per fat
            uint16_t flags;            // flags
            uint16_t fat_ver;          // fat version
            uint32_t rootdir_clusters; // cluster which is root director
            uint16_t fsinfo_sector;    // fsinfo sectors
            uint16_t backup_sector;    // bootsec backup
            uint8_t reserved[12];
            uint8_t driver;           // driver number
            uint8_t ntflag;           // nt flag
            uint8_t signature;        // must be 0x28 or 0x29
            uint32_t volumeID;        // volumeID
            uint8_t volume_label[11]; // volume label string
            uint8_t sysid_string[8];  // fs identify string,fat32 is 'FAT32'
            uint8_t boot_code[420];   // boot code
        } fat32;
        struct
        {
            uint8_t driver;           // driver number
            uint8_t ntflags;          // nt flags
            uint8_t signature;        // must be 0x28 or 0x29
            uint32_t volumeID;        // volumeID
            uint8_t volume_label[11]; // volume label string
            uint8_t sysid_string[8];  // fs identify string
            uint8_t boot_code[448];   // boot code
        } fat;
    } exbpb;
    uint16_t magic; // must be 0xaa55
} bpb_t;
#pragma pack(pop)

#define XDIR_SUM 2

#define XBPB_VOLSTATUS 106
#define XBPB_USING 112

// exFAT boot block
#pragma pack(push, 1)
typedef struct
{
    uint8_t jmp[3]; // jmp instruction
    uint8_t oem[8]; //"EXFAT   "
    uint8_t unused1[53];
    uint64_t start_sector;  // partition start sector
    uint64_t total_size;    // partiton sector size
    uint32_t fat_sector;    // fat start sector
    uint32_t fat_size;      // fat sector size
    uint32_t clust_sector;  // first cluster start sector
    uint32_t clust_count;   // total cluster count
    uint32_t rootdir_clust; // root first cluster number
    uint32_t vol_id;        // volume serial id
    uint16_t vol_ver;       // volume version
    uint16_t vol_status;    // volume status
    uint8_t sector_size;    // bytes per sector
    uint8_t clust_size;     // sectors per cluster
    uint8_t fat_count;      // fat table count
    uint8_t driver_flags;   // driver flags;
    uint8_t used_status;    // cluster use status
    uint8_t reserved[7];
    uint8_t boot_code[390]; // boot code
    uint16_t magic;         // magic
} xbpb_t;
#pragma pack(pop)

// mkfs parame block
typedef struct
{
    uint8_t fmt;          // format
    uint8_t fat_num;      // number of FAT
    uint32_t align;       // align sector
    uint32_t rootdir_num; // rootdir entry number
    uint64_t clust_size;  // clust size
} mkfs_parm_t;

/* SBCS up-case tables (\x80-\xFF) */
#define TBL_CT437                                                                                           \
    {                                                                                                       \
        0x80, 0x9A, 0x45, 0x41, 0x8E, 0x41, 0x8F, 0x80, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x8E, 0x8F,     \
            0x90, 0x92, 0x92, 0x4F, 0x99, 0x4F, 0x55, 0x55, 0x59, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, \
            0x41, 0x49, 0x4F, 0x55, 0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \
            0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, \
            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT720                                                                                           \
    {                                                                                                       \
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,     \
            0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, \
            0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \
            0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, \
            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT737                                                                                           \
    {                                                                                                       \
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,     \
            0x90, 0x92, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, \
            0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0xAA, 0x92, 0x93, 0x94, 0x95, 0x96, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \
            0x97, 0xEA, 0xEB, 0xEC, 0xE4, 0xED, 0xEE, 0xEF, 0xF5, 0xF0, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, \
            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT771                                                                                           \
    {                                                                                                       \
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,     \
            0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, \
            0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDC, 0xDE, 0xDE, \
            0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, \
            0xF0, 0xF0, 0xF2, 0xF2, 0xF4, 0xF4, 0xF6, 0xF6, 0xF8, 0xF8, 0xFA, 0xFA, 0xFC, 0xFC, 0xFE, 0xFF  \
    }
#define TBL_CT775                                                                                           \
    {                                                                                                       \
        0x80, 0x9A, 0x91, 0xA0, 0x8E, 0x95, 0x8F, 0x80, 0xAD, 0xED, 0x8A, 0x8A, 0xA1, 0x8D, 0x8E, 0x8F,     \
            0x90, 0x92, 0x92, 0xE2, 0x99, 0x95, 0x96, 0x97, 0x97, 0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9F, \
            0xA0, 0xA1, 0xE0, 0xA3, 0xA3, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xB5, 0xB6, 0xB7, 0xB8, 0xBD, 0xBE, 0xC6, 0xC7, 0xA5, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \
            0xE0, 0xE1, 0xE2, 0xE3, 0xE5, 0xE5, 0xE6, 0xE3, 0xE8, 0xE8, 0xEA, 0xEA, 0xEE, 0xED, 0xEE, 0xEF, \
            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT850                                                                                           \
    {                                                                                                       \
        0x43, 0x55, 0x45, 0x41, 0x41, 0x41, 0x41, 0x43, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x41, 0x41,     \
            0x45, 0x92, 0x92, 0x4F, 0x4F, 0x4F, 0x55, 0x55, 0x59, 0x4F, 0x55, 0x4F, 0x9C, 0x4F, 0x9E, 0x9F, \
            0x41, 0x49, 0x4F, 0x55, 0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0x41, 0x41, 0x41, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0x41, 0x41, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD1, 0xD1, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0x49, 0xDF, \
            0x4F, 0xE1, 0x4F, 0x4F, 0x4F, 0x4F, 0xE6, 0xE8, 0xE8, 0x55, 0x55, 0x55, 0x59, 0x59, 0xEE, 0xEF, \
            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT852                                                                                           \
    {                                                                                                       \
        0x80, 0x9A, 0x90, 0xB6, 0x8E, 0xDE, 0x8F, 0x80, 0x9D, 0xD3, 0x8A, 0x8A, 0xD7, 0x8D, 0x8E, 0x8F,     \
            0x90, 0x91, 0x91, 0xE2, 0x99, 0x95, 0x95, 0x97, 0x97, 0x99, 0x9A, 0x9B, 0x9B, 0x9D, 0x9E, 0xAC, \
            0xB5, 0xD6, 0xE0, 0xE9, 0xA4, 0xA4, 0xA6, 0xA6, 0xA8, 0xA8, 0xAA, 0x8D, 0xAC, 0xB8, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBD, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC6, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD1, 0xD1, 0xD2, 0xD3, 0xD2, 0xD5, 0xD6, 0xD7, 0xB7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \
            0xE0, 0xE1, 0xE2, 0xE3, 0xE3, 0xD5, 0xE6, 0xE6, 0xE8, 0xE9, 0xE8, 0xEB, 0xED, 0xED, 0xDD, 0xEF, \
            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xEB, 0xFC, 0xFC, 0xFE, 0xFF  \
    }
#define TBL_CT855                                                                                           \
    {                                                                                                       \
        0x81, 0x81, 0x83, 0x83, 0x85, 0x85, 0x87, 0x87, 0x89, 0x89, 0x8B, 0x8B, 0x8D, 0x8D, 0x8F, 0x8F,     \
            0x91, 0x91, 0x93, 0x93, 0x95, 0x95, 0x97, 0x97, 0x99, 0x99, 0x9B, 0x9B, 0x9D, 0x9D, 0x9F, 0x9F, \
            0xA1, 0xA1, 0xA3, 0xA3, 0xA5, 0xA5, 0xA7, 0xA7, 0xA9, 0xA9, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB6, 0xB6, 0xB8, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBE, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC7, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD1, 0xD1, 0xD3, 0xD3, 0xD5, 0xD5, 0xD7, 0xD7, 0xDD, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xE0, 0xDF, \
            0xE0, 0xE2, 0xE2, 0xE4, 0xE4, 0xE6, 0xE6, 0xE8, 0xE8, 0xEA, 0xEA, 0xEC, 0xEC, 0xEE, 0xEE, 0xEF, \
            0xF0, 0xF2, 0xF2, 0xF4, 0xF4, 0xF6, 0xF6, 0xF8, 0xF8, 0xFA, 0xFA, 0xFC, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT857                                                                                           \
    {                                                                                                       \
        0x80, 0x9A, 0x90, 0xB6, 0x8E, 0xB7, 0x8F, 0x80, 0xD2, 0xD3, 0xD4, 0xD8, 0xD7, 0x49, 0x8E, 0x8F,     \
            0x90, 0x92, 0x92, 0xE2, 0x99, 0xE3, 0xEA, 0xEB, 0x98, 0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9E, \
            0xB5, 0xD6, 0xE0, 0xE9, 0xA5, 0xA5, 0xA6, 0xA6, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC7, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0x49, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \
            0xE0, 0xE1, 0xE2, 0xE3, 0xE5, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xDE, 0xED, 0xEE, 0xEF, \
            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT860                                                                                           \
    {                                                                                                       \
        0x80, 0x9A, 0x90, 0x8F, 0x8E, 0x91, 0x86, 0x80, 0x89, 0x89, 0x92, 0x8B, 0x8C, 0x98, 0x8E, 0x8F,     \
            0x90, 0x91, 0x92, 0x8C, 0x99, 0xA9, 0x96, 0x9D, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, \
            0x86, 0x8B, 0x9F, 0x96, 0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \
            0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, \
            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT861                                                                                           \
    {                                                                                                       \
        0x80, 0x9A, 0x90, 0x41, 0x8E, 0x41, 0x8F, 0x80, 0x45, 0x45, 0x45, 0x8B, 0x8B, 0x8D, 0x8E, 0x8F,     \
            0x90, 0x92, 0x92, 0x4F, 0x99, 0x8D, 0x55, 0x97, 0x97, 0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9F, \
            0xA4, 0xA5, 0xA6, 0xA7, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \
            0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, \
            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT862                                                                                           \
    {                                                                                                       \
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,     \
            0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, \
            0x41, 0x49, 0x4F, 0x55, 0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \
            0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, \
            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT863                                                                                           \
    {                                                                                                       \
        0x43, 0x55, 0x45, 0x41, 0x41, 0x41, 0x86, 0x43, 0x45, 0x45, 0x45, 0x49, 0x49, 0x8D, 0x41, 0x8F,     \
            0x45, 0x45, 0x45, 0x4F, 0x45, 0x49, 0x55, 0x55, 0x98, 0x4F, 0x55, 0x9B, 0x9C, 0x55, 0x55, 0x9F, \
            0xA0, 0xA1, 0x4F, 0x55, 0xA4, 0xA5, 0xA6, 0xA7, 0x49, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \
            0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, \
            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT864                                                                                           \
    {                                                                                                       \
        0x80, 0x9A, 0x45, 0x41, 0x8E, 0x41, 0x8F, 0x80, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x8E, 0x8F,     \
            0x90, 0x92, 0x92, 0x4F, 0x99, 0x4F, 0x55, 0x55, 0x59, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, \
            0x41, 0x49, 0x4F, 0x55, 0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \
            0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, \
            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT865                                                                                           \
    {                                                                                                       \
        0x80, 0x9A, 0x90, 0x41, 0x8E, 0x41, 0x8F, 0x80, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x8E, 0x8F,     \
            0x90, 0x92, 0x92, 0x4F, 0x99, 0x4F, 0x55, 0x55, 0x59, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, \
            0x41, 0x49, 0x4F, 0x55, 0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \
            0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, \
            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT866                                                                                           \
    {                                                                                                       \
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,     \
            0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, \
            0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \
            0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, \
            0xF0, 0xF0, 0xF2, 0xF2, 0xF4, 0xF4, 0xF6, 0xF6, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF  \
    }
#define TBL_CT869                                                                                           \
    {                                                                                                       \
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,     \
            0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x86, 0x9C, 0x8D, 0x8F, 0x90, \
            0x91, 0x90, 0x92, 0x95, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, \
            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, \
            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, \
            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xA4, 0xA5, 0xA6, 0xD9, 0xDA, 0xDB, 0xDC, 0xA7, 0xA8, 0xDF, \
            0xA9, 0xAA, 0xAC, 0xAD, 0xB5, 0xB6, 0xB7, 0xB8, 0xBD, 0xBE, 0xC6, 0xC7, 0xCF, 0xCF, 0xD0, 0xEF, \
            0xF0, 0xF1, 0xD1, 0xD2, 0xD3, 0xF5, 0xD4, 0xF7, 0xF8, 0xF9, 0xD5, 0x96, 0x95, 0x98, 0xFE, 0xFF  \
    }

/* DBCS code range |----- 1st byte -----|  |----------- 2nd byte -----------| */
/*                  <------>    <------>    <------>    <------>    <------>  */
#define TBL_DC932                                                  \
    {                                                              \
        0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00 \
    }
#define TBL_DC936                                                  \
    {                                                              \
        0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0x80, 0xFE, 0x00, 0x00 \
    }
#define TBL_DC949                                                  \
    {                                                              \
        0x81, 0xFE, 0x00, 0x00, 0x41, 0x5A, 0x61, 0x7A, 0x81, 0xFE \
    }
#define TBL_DC950                                                  \
    {                                                              \
        0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0xA1, 0xFE, 0x00, 0x00 \
    }

// mecro for table definitions
#define MERGE_2STR(a, b) a##b
#define MKCVTBL(oem, code) MERGE_2STR(oem, code)

#if FS_CODE_PAGE == 0 /* Run-time code page configuration */
#define CODEPAGE CodePage
static WORD CodePage;              /* Current code page */
static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */

static const BYTE Ct437[] = TBL_CT437;
static const BYTE Ct720[] = TBL_CT720;
static const BYTE Ct737[] = TBL_CT737;
static const BYTE Ct771[] = TBL_CT771;
static const BYTE Ct775[] = TBL_CT775;
static const BYTE Ct850[] = TBL_CT850;
static const BYTE Ct852[] = TBL_CT852;
static const BYTE Ct855[] = TBL_CT855;
static const BYTE Ct857[] = TBL_CT857;
static const BYTE Ct860[] = TBL_CT860;
static const BYTE Ct861[] = TBL_CT861;
static const BYTE Ct862[] = TBL_CT862;
static const BYTE Ct863[] = TBL_CT863;
static const BYTE Ct864[] = TBL_CT864;
static const BYTE Ct865[] = TBL_CT865;
static const BYTE Ct866[] = TBL_CT866;
static const BYTE Ct869[] = TBL_CT869;
static const BYTE Dc932[] = TBL_DC932;
static const BYTE Dc936[] = TBL_DC936;
static const BYTE Dc949[] = TBL_DC949;
static const BYTE Dc950[] = TBL_DC950;

#elif FS_CODE_PAGE < 900 /* Static code page configuration (SBCS) */
#define CODEPAGE FS_CODE_PAGE
static const BYTE ExCvt[] = MKCVTBL(TBL_CT, FS_CODE_PAGE);

#else /* Static code page configuration (DBCS) */
#define CODEPAGE FS_CODE_PAGE
static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FS_CODE_PAGE);
#endif

// fat fs sync type
typedef semaphore_t *fs_sync_t;

// fs function
file_status_t FileOpen(file_obj_t *fp, const char *path, uint32_t mode);
file_status_t FileClose(file_obj_t *file);
file_status_t FileOpenDir(dir_obj_t *dir, const char *path);
file_status_t FileCloseDir(dir_obj_t *dir);
file_status_t FileStatus(const char *path, file_info_t *fno);
file_status_t FileTruncate(file_obj_t *fp);
file_status_t FileUnlink(const char *path);

file_status_t FileRead(file_obj_t *fp, void *buff, uint32_t bytes, uint32_t *reads);
file_status_t FileWrite(file_obj_t *fp, void *buff, uint32_t bytes, uint32_t *writes);
file_status_t FileSync(file_obj_t *obj);
file_status_t FileChDriver(const char *path);
file_status_t FileChDir(const char *path);
file_status_t FileGetCwd(uint8_t *buff, uint32_t len);
file_status_t FileLSeek(file_obj_t *obj, uint32_t off);
file_status_t FileMkDir(const char *path);
file_status_t FileMount(fatfs_t *fs, const char *path, uint8_t op);
file_status_t FileReadDir(dir_obj_t *dir, file_info_t *fno);
file_status_t FileRename(const char *path_old, const char *path_new);
file_status_t FileMkFs(const char *path, mkfs_parm_t *op, void *work, uint32_t len);
file_status_t FileUtime(const char *path, file_info_t *finfo);

#define FileEof(fp) ((fp)->fptr = (fp)->obj.size)
#define FileError(fp) ((fp)->err)
#define FileTell(fp) ((fp)->fptr)
#define FileSize(fp) ((fp)->obj.size)
#define FileRewind(fp) FileLSeek((fp), 0)
#define FileRewindDir(dp) FileReadDir((dp), 0)
#define FileRmDir(path) FileUnlink(path)
#define FileUnmount(path) FileMount(0, path, 0)

#endif
